package com.yinhd.study.customLog;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import static java.lang.System.out;

/**
 * @program: study
 * @description:
 * @Author: chengl
 * @create: 2022-02-09 10:32
 **/
@Component
@Aspect
public class OperationLogAop {
    @Autowired
    LogDTO logDTO;

    public  static HashMap<String, String> requestMap = new HashMap<String, String>();
    @PostConstruct
    public  Map<String, String> getTypeCodeMap() {
        if(requestMap.size() == 0){
            RequestTypeUtils[] values = RequestTypeUtils.values();
            for (RequestTypeUtils c : values) {
                requestMap.put(c.type,c.value);
            }
        }
        return requestMap;
    }

    // 需要被SpEl解析的模板前缀和后缀 {{ expression  }}
    public static final TemplateParserContext TEMPLATE_PARSER_CONTEXT = new TemplateParserContext("{{", "}}");

    // SpEL解析器
    public static final ExpressionParser EXPRESSION_PARSER = new SpelExpressionParser();

    @Pointcut(value = "@annotation(com.yinhd.study.customLog.OperationLog)")
    public void saveLog() {

    }

    @AfterReturning(returning = "object", pointcut = "saveLog()")
    public void actionLog(JoinPoint joinPoint, Object object) throws Throwable {

        StringBuilder log = new StringBuilder();

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        // 参数
        Object[] args = joinPoint.getArgs();
        // 参数名称
        String[] parameterNames = signature.getParameterNames();
        // 目标方法
        Method targetMethod = signature.getMethod();
        // 方法上的日志注解
        OperationLog operationLog = targetMethod.getAnnotation(OperationLog.class);
        // request
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        // response
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();

        String requestMethod = request.getMethod();

        //信息收集匹配
        Map<String, Object> collect = new HashMap<>();
        for (int i = 0; i < args.length; i++) {
            collect.put(parameterNames[i], args[i]);
        }
            Class<?> aClass = object.getClass();
            Field[] declaredFields = aClass.getDeclaredFields();
            for (Field f : declaredFields) {
                f.setAccessible(true);
                collect.put(f.getName(), f.get(object));
            }
        //        status = resultCode == 0 ? "成功" : "失败";
        //        out.println(userName + action + objects + status);

        //log信息拼接
        log.append(StringUtils.hasLength(operationLog.operator()) ? operationLog.operator() : "根据请求自动获取")
                .append(StringUtils.hasLength(operationLog.action()) ? operationLog.action() : requestMap.get(requestMethod))  //操作类型
                .append(StringUtils.hasLength(operationLog.heir()) ? operationLog.heir() : "")
                .append(StringUtils.hasLength(operationLog.content()) ? operationLog.content() : "")
                .append(StringUtils.hasLength(operationLog.state()) ? operationLog.state() : collect.get("resultCode")
                        .equals(0) ? "成功" : "失败");

        try {
            /**
             * SpEL解析的上下文，把 HandlerMethod 的形参都添加到上下文中，并且使用参数名称作为KEY
             */
            EvaluationContext evaluationContext = new StandardEvaluationContext();
            for (String key : collect.keySet()) {
                evaluationContext.setVariable(key, collect.get(key));
            }

            String logContent = EXPRESSION_PARSER.parseExpression(log.toString(), TEMPLATE_PARSER_CONTEXT)
                    .getValue(evaluationContext, String.class);

            out.println("logContent:" + logContent);
            // TODO 异步存储日志
            // log.info("operationLog={}", logContent);
        } catch (Exception e) {
            out.println("操作日志SpEL表达式解析异常:" + e.toString());
        }

    }




}
